//
// Created by tcj on 2022/3/2.
//
/*
 * 继承自协程调度模块，封装了epoll。支持为sokcet fd注册读写时间回调函数
 * io模块解决了调度器在idle状态下忙等待导致cpu占用率高的问题
 * io协程调度器使用以堆管道fd来tickle调度协程，
 *      当调度器空闲时，idle协程通过epoll_wait阻塞在管道的读描述符上，
 *              等管道的可读时间。
*     添加新任务的时候，tickle方法写管道，idle协程检测到管道可读后退出，调度器执行调度
 *
 *
 *
 * 基类中已经实现并且继续使用的函数：
 *          start():开启调度器运行
 *          stop(): 停止调度器运行
 *          run(): 这个函数真正执行调度逻辑
 *          scheduleNolock（）  将任务加入队列
 *
 * 派生类中实现的核心类：
 *         tickle():线程唤醒
 *         stopping():判断调度器是否可以停止
 *         idle():协程没有任务可以做的时候，借用epoll_wait()来唤醒有任务可执行
 *
 * */




#ifndef SYLAR_IOMANAGER_H__
#define SYLAR_IOMANAGER_H__

#include "scheduler.h"
#include "timer.h"
/*
 * 对于io调度来说，，每次调度就是一个三元组信息
 *             描述符，事件类型，回调函数
*  描述符，事件类型--》就是用来epoll_wait  回调函数就是用来协程调度的
 *  三元组信息就是通过Fdcontext结构体进行保存
 * */
namespace sylar{
//  基于epoll的io协程调度器
/*
 * iomanager通过继承获得timermanager类的所有方法
 *
 * */
    class IOManager :public Scheduler,public TimerManager{
    public:
        typedef std::shared_ptr<IOManager> ptr;
        typedef RWMutex RWMutexType;

//        io事件
        enum Event{
            NONE = 0X0,//无事件
            READ = 0X1,  //EPOLLIN   读事件
            WRITE = 0X4, //EPOLLOUT  写事件
        };
    private:
        //socket事件上线文类
        struct FdContext{
            typedef Mutex MutexType;
            struct EventContext{
                Scheduler* scheduler;   //（事件执行的调度器）
                                        // 待执行的scheduler
                Fiber::ptr  fiber;      //事件协程
                std::function<void()> cb;//事件的回调函数
            };

            //获取事件的上下文类
            EventContext& getContext(Event event);
            //重置事件的上下文类
            void resetContext(EventContext& ctx);
            //触发事件
            void triggerEvent(Event event);


            EventContext read;      //读事件上下文
            EventContext write;     //写事件上下文
            int fd=0;                 //事件关联的句柄
            //已经注册的事件（当前的事件）  该fd添加了哪些事件的回调函数，或者说该fd关心哪些事件
            Event events = NONE;
            MutexType mutex;

        };

    public:

        IOManager(size_t threads =1,bool use_caller=true,const std::string& name="");
        ~IOManager();

        //1.success  0.retry  -1.error
//        添加事件
        int addEvent(int fd,Event event,std::function<void()> cb = nullptr);
        //删除事件
        bool delEvent(int fd,Event event);
        //取消事件
        bool cancelEvent(int fd,Event event);
        //取消所有事件
        bool cancalAll(int fd);
        //返回当前的iomanager
        static IOManager* GetThis();

    protected:
        //
        void tickle() override;
        bool stopping() override;
        void idle() override;
        void onTimerInsertedAtFront() override;
//        判断是否可以停止
        bool stopping(uint64_t& timeout);
        //重置sokcet句柄上下文容器的大小
        void contextResize(size_t size);
    private:
//        epoll文件句柄
        int m_epfd =0;
//      pipe文件句柄
        int m_tickleFds[2];
        //当前等待执行的事件数量
        std::atomic<size_t> m_pendingEventCount = {0};
        RWMutexType m_mutex;
        //socket事件上下文的容器
        std::vector<FdContext*> m_fdContexts;

    };
}


#endif //SERVER_FRAMEWORK_IOMANAGER_H
